<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="generator" content="VuePress 2.0.0-beta.61">
    <style>
      :root {
        --c-bg: #fff;
      }
      html.dark {
        --c-bg: #22272e;
      }
      html, body {
        background-color: var(--c-bg);
      }
    </style>
    <script>
      const userMode = localStorage.getItem('vuepress-color-scheme');
			const systemDarkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
			if (userMode === 'dark' || (userMode !== 'light' && systemDarkMode)) {
				document.documentElement.classList.toggle('dark', true);
			}
    </script>
    <script type="text/javascript" src="/lib/tinymce5.10.5/tinymce.min.js"></script><title>熟悉而陌生的模块化（全面剖析 CommonJs 和 ES6Module） | JN Frontend Docs</title><meta name="description" content="江苏金农股份有限公司前端文档站，站内包含内部组件库、微前端框架等文档">
    <link rel="preload" href="/assets/style-7f06fc9f.css" as="style"><link rel="stylesheet" href="/assets/style-7f06fc9f.css">
    <link rel="modulepreload" href="/assets/app-bfaa94ab.js"><link rel="modulepreload" href="/assets/framework-340c2a10.js"><link rel="modulepreload" href="/assets/熟悉而陌生的模块化.html-4ff45b9c.js"><link rel="modulepreload" href="/assets/熟悉而陌生的模块化.html-9f3227d8.js"><link rel="prefetch" href="/assets/index.html-c08dba9c.js" as="script"><link rel="prefetch" href="/assets/index.html-db435b79.js" as="script"><link rel="prefetch" href="/assets/letconst.html-3b192b16.js" as="script"><link rel="prefetch" href="/assets/Address.html-f7647e70.js" as="script"><link rel="prefetch" href="/assets/BaseDrawerContent.html-ab3037a8.js" as="script"><link rel="prefetch" href="/assets/BaseModule.html-1478fa1c.js" as="script"><link rel="prefetch" href="/assets/ButtonGroup.html-fcf3a331.js" as="script"><link rel="prefetch" href="/assets/Collapse.html-7a8cea51.js" as="script"><link rel="prefetch" href="/assets/DebounceButton.html-72c7ad85.js" as="script"><link rel="prefetch" href="/assets/FigureInput.html-df25dc00.js" as="script"><link rel="prefetch" href="/assets/FilePreview.html-4937fb57.js" as="script"><link rel="prefetch" href="/assets/Form.html-5d6b22f4.js" as="script"><link rel="prefetch" href="/assets/HintBox.html-6835dcbd.js" as="script"><link rel="prefetch" href="/assets/Icon.html-607be958.js" as="script"><link rel="prefetch" href="/assets/IconPicker.html-81fcc2d0.js" as="script"><link rel="prefetch" href="/assets/IrregularTable.html-3334208c.js" as="script"><link rel="prefetch" href="/assets/JnEditor.html-f19354db.js" as="script"><link rel="prefetch" href="/assets/LodingShade.html-ce32f5ba.js" as="script"><link rel="prefetch" href="/assets/Modal.html-1a4aba4c.js" as="script"><link rel="prefetch" href="/assets/OperateExcel.html-13779fda.js" as="script"><link rel="prefetch" href="/assets/SelectTree.html-8eb35b5a.js" as="script"><link rel="prefetch" href="/assets/SelectTreeV2.html-0294e83a.js" as="script"><link rel="prefetch" href="/assets/Table.html-e8baa24a.js" as="script"><link rel="prefetch" href="/assets/Tabs.html-f99f83c2.js" as="script"><link rel="prefetch" href="/assets/Tree.html-94f64c00.js" as="script"><link rel="prefetch" href="/assets/UpdateLog.html-96fed179.js" as="script"><link rel="prefetch" href="/assets/Updateguide.html-d24798ff.js" as="script"><link rel="prefetch" href="/assets/Upload.html-5d77d402.js" as="script"><link rel="prefetch" href="/assets/index.html-b65ce016.js" as="script"><link rel="prefetch" href="/assets/index.html-fe9f70c5.js" as="script"><link rel="prefetch" href="/assets/moenorepo.html-6096f1b5.js" as="script"><link rel="prefetch" href="/assets/subPro.html-36f639d2.js" as="script"><link rel="prefetch" href="/assets/FAQ.html-4ecdac2c.js" as="script"><link rel="prefetch" href="/assets/commitMsg.html-307d426c.js" as="script"><link rel="prefetch" href="/assets/construction.html-99aa1b4d.js" as="script"><link rel="prefetch" href="/assets/environmentVar.html-49d04c3a.js" as="script"><link rel="prefetch" href="/assets/homeDev.html-6a2fb1a0.js" as="script"><link rel="prefetch" href="/assets/index.html-0b6e8117.js" as="script"><link rel="prefetch" href="/assets/microRegList.html-b62877d4.js" as="script"><link rel="prefetch" href="/assets/plan.html-277e3cea.js" as="script"><link rel="prefetch" href="/assets/practice.html-c4d36b33.js" as="script"><link rel="prefetch" href="/assets/production.html-dc42f69e.js" as="script"><link rel="prefetch" href="/assets/quickStart-monorepo.html-7b3b7f8d.js" as="script"><link rel="prefetch" href="/assets/quickStart.html-b6e33c48.js" as="script"><link rel="prefetch" href="/assets/quickStart2.html-b10000c3.js" as="script"><link rel="prefetch" href="/assets/scheme.html-d542f716.js" as="script"><link rel="prefetch" href="/assets/storeMage.html-815c6185.js" as="script"><link rel="prefetch" href="/assets/theme.html-465ca127.js" as="script"><link rel="prefetch" href="/assets/v1ToV2.html-9a2bc18d.js" as="script"><link rel="prefetch" href="/assets/workflow.html-6e534c27.js" as="script"><link rel="prefetch" href="/assets/index.html-81fa1c2b.js" as="script"><link rel="prefetch" href="/assets/painSpot.html-77e2c96b.js" as="script"><link rel="prefetch" href="/assets/resolve.html-2a8f8dad.js" as="script"><link rel="prefetch" href="/assets/index.html-bdc10a52.js" as="script"><link rel="prefetch" href="/assets/bom.html-ced4003b.js" as="script"><link rel="prefetch" href="/assets/dom.html-3d9c1f79.js" as="script"><link rel="prefetch" href="/assets/download.html-fc87bd6a.js" as="script"><link rel="prefetch" href="/assets/index.html-193d1a36.js" as="script"><link rel="prefetch" href="/assets/install.html-c6c6b180.js" as="script"><link rel="prefetch" href="/assets/number.html-9929ee21.js" as="script"><link rel="prefetch" href="/assets/object.html-62e9bd7c.js" as="script"><link rel="prefetch" href="/assets/storage.html-438a0e0f.js" as="script"><link rel="prefetch" href="/assets/string.html-66b8ad68.js" as="script"><link rel="prefetch" href="/assets/tree.html-6b8c9496.js" as="script"><link rel="prefetch" href="/assets/FormGenerate.html-493fc23c.js" as="script"><link rel="prefetch" href="/assets/Bar.html-ba9fe5e8.js" as="script"><link rel="prefetch" href="/assets/Basic.html-e8fb918f.js" as="script"><link rel="prefetch" href="/assets/Line.html-4604e09a.js" as="script"><link rel="prefetch" href="/assets/Pie.html-c30a8814.js" as="script"><link rel="prefetch" href="/assets/InfoAutocomplete.html-00b41d3e.js" as="script"><link rel="prefetch" href="/assets/InfoSelect.html-671c17bd.js" as="script"><link rel="prefetch" href="/assets/InfoSelectAll.html-9008c8b4.js" as="script"><link rel="prefetch" href="/assets/assets.html-260242e8.js" as="script"><link rel="prefetch" href="/assets/componentConcept.html-6e4317dc.js" as="script"><link rel="prefetch" href="/assets/componentPractical.html-9086711f.js" as="script"><link rel="prefetch" href="/assets/directives.html-d0ae2312.js" as="script"><link rel="prefetch" href="/assets/indexes.html-e77392a8.js" as="script"><link rel="prefetch" href="/assets/pageContentAuths.html-4d589490.js" as="script"><link rel="prefetch" href="/assets/pages.html-c55a8bc5.js" as="script"><link rel="prefetch" href="/assets/requestApi.html-88bb2797.js" as="script"><link rel="prefetch" href="/assets/requestConcept.html-adda0d11.js" as="script"><link rel="prefetch" href="/assets/requestPractical.html-faecae2b.js" as="script"><link rel="prefetch" href="/assets/requestProxy.html-3200aa1f.js" as="script"><link rel="prefetch" href="/assets/routerConcept.html-6accad32.js" as="script"><link rel="prefetch" href="/assets/routerPractical.html-512c6707.js" as="script"><link rel="prefetch" href="/assets/storeConcept.html-e22e9ac7.js" as="script"><link rel="prefetch" href="/assets/storePractical.html-247d8533.js" as="script"><link rel="prefetch" href="/assets/typesConcept.html-e1076ad0.js" as="script"><link rel="prefetch" href="/assets/typesPractical.html-a063ac6b.js" as="script"><link rel="prefetch" href="/assets/basic-old.html-e813c095.js" as="script"><link rel="prefetch" href="/assets/basic.html-96becbed.js" as="script"><link rel="prefetch" href="/assets/dependence.html-43d38fc7.js" as="script"><link rel="prefetch" href="/assets/micro-od.html-9dfcee74.js" as="script"><link rel="prefetch" href="/assets/micro.html-c39098c6.js" as="script"><link rel="prefetch" href="/assets/404.html-f9875e7b.js" as="script"><link rel="prefetch" href="/assets/index.html-48aa5787.js" as="script"><link rel="prefetch" href="/assets/index.html-d608a849.js" as="script"><link rel="prefetch" href="/assets/letconst.html-3f2e0b96.js" as="script"><link rel="prefetch" href="/assets/Address.html-42ef6369.js" as="script"><link rel="prefetch" href="/assets/BaseDrawerContent.html-ca2f5dbf.js" as="script"><link rel="prefetch" href="/assets/BaseModule.html-bcac5fb3.js" as="script"><link rel="prefetch" href="/assets/ButtonGroup.html-45240bc0.js" as="script"><link rel="prefetch" href="/assets/Collapse.html-2820a639.js" as="script"><link rel="prefetch" href="/assets/DebounceButton.html-a6375e54.js" as="script"><link rel="prefetch" href="/assets/FigureInput.html-6a9e4a73.js" as="script"><link rel="prefetch" href="/assets/FilePreview.html-f7c5e9fe.js" as="script"><link rel="prefetch" href="/assets/Form.html-3068bdf0.js" as="script"><link rel="prefetch" href="/assets/HintBox.html-bbf1cd9e.js" as="script"><link rel="prefetch" href="/assets/Icon.html-d95e3688.js" as="script"><link rel="prefetch" href="/assets/IconPicker.html-81a7e524.js" as="script"><link rel="prefetch" href="/assets/IrregularTable.html-a890399c.js" as="script"><link rel="prefetch" href="/assets/JnEditor.html-bf85cd36.js" as="script"><link rel="prefetch" href="/assets/LodingShade.html-c0d28ff3.js" as="script"><link rel="prefetch" href="/assets/Modal.html-794dcc40.js" as="script"><link rel="prefetch" href="/assets/OperateExcel.html-b0ba91a0.js" as="script"><link rel="prefetch" href="/assets/SelectTree.html-595c0e38.js" as="script"><link rel="prefetch" href="/assets/SelectTreeV2.html-34bccf21.js" as="script"><link rel="prefetch" href="/assets/Table.html-d73c36b9.js" as="script"><link rel="prefetch" href="/assets/Tabs.html-84faed0a.js" as="script"><link rel="prefetch" href="/assets/Tree.html-3667a114.js" as="script"><link rel="prefetch" href="/assets/UpdateLog.html-4a1f3631.js" as="script"><link rel="prefetch" href="/assets/Updateguide.html-02371534.js" as="script"><link rel="prefetch" href="/assets/Upload.html-10ba1ca0.js" as="script"><link rel="prefetch" href="/assets/index.html-c47a30df.js" as="script"><link rel="prefetch" href="/assets/index.html-320567a6.js" as="script"><link rel="prefetch" href="/assets/moenorepo.html-576011bb.js" as="script"><link rel="prefetch" href="/assets/subPro.html-75b57a23.js" as="script"><link rel="prefetch" href="/assets/FAQ.html-f1fca6c0.js" as="script"><link rel="prefetch" href="/assets/commitMsg.html-6acdc46a.js" as="script"><link rel="prefetch" href="/assets/construction.html-46da6ea7.js" as="script"><link rel="prefetch" href="/assets/environmentVar.html-cc5e18a8.js" as="script"><link rel="prefetch" href="/assets/homeDev.html-45d74a50.js" as="script"><link rel="prefetch" href="/assets/index.html-957a05f9.js" as="script"><link rel="prefetch" href="/assets/microRegList.html-58159017.js" as="script"><link rel="prefetch" href="/assets/plan.html-f544d172.js" as="script"><link rel="prefetch" href="/assets/practice.html-9190a049.js" as="script"><link rel="prefetch" href="/assets/production.html-efcd58ad.js" as="script"><link rel="prefetch" href="/assets/quickStart-monorepo.html-fa679827.js" as="script"><link rel="prefetch" href="/assets/quickStart.html-b2b2cf91.js" as="script"><link rel="prefetch" href="/assets/quickStart2.html-f4e9daf8.js" as="script"><link rel="prefetch" href="/assets/scheme.html-554f0667.js" as="script"><link rel="prefetch" href="/assets/storeMage.html-6e8d9e82.js" as="script"><link rel="prefetch" href="/assets/theme.html-769f6eb6.js" as="script"><link rel="prefetch" href="/assets/v1ToV2.html-3ae59d40.js" as="script"><link rel="prefetch" href="/assets/workflow.html-9f9833c6.js" as="script"><link rel="prefetch" href="/assets/index.html-3970f3cb.js" as="script"><link rel="prefetch" href="/assets/painSpot.html-24db33c6.js" as="script"><link rel="prefetch" href="/assets/resolve.html-84653b13.js" as="script"><link rel="prefetch" href="/assets/index.html-b7232fce.js" as="script"><link rel="prefetch" href="/assets/bom.html-ea3a3186.js" as="script"><link rel="prefetch" href="/assets/dom.html-9edcb1e4.js" as="script"><link rel="prefetch" href="/assets/download.html-4dd3d345.js" as="script"><link rel="prefetch" href="/assets/index.html-b478f1d0.js" as="script"><link rel="prefetch" href="/assets/install.html-3a798661.js" as="script"><link rel="prefetch" href="/assets/number.html-f73b01de.js" as="script"><link rel="prefetch" href="/assets/object.html-3bffe94b.js" as="script"><link rel="prefetch" href="/assets/storage.html-02163cce.js" as="script"><link rel="prefetch" href="/assets/string.html-2368bc12.js" as="script"><link rel="prefetch" href="/assets/tree.html-795d0257.js" as="script"><link rel="prefetch" href="/assets/FormGenerate.html-112e9811.js" as="script"><link rel="prefetch" href="/assets/Bar.html-b734d02b.js" as="script"><link rel="prefetch" href="/assets/Basic.html-8aa29fd5.js" as="script"><link rel="prefetch" href="/assets/Line.html-0006a111.js" as="script"><link rel="prefetch" href="/assets/Pie.html-e5d8de5a.js" as="script"><link rel="prefetch" href="/assets/InfoAutocomplete.html-335586cf.js" as="script"><link rel="prefetch" href="/assets/InfoSelect.html-19b6bfa4.js" as="script"><link rel="prefetch" href="/assets/InfoSelectAll.html-ba486e6d.js" as="script"><link rel="prefetch" href="/assets/assets.html-c2237689.js" as="script"><link rel="prefetch" href="/assets/componentConcept.html-d44f97dc.js" as="script"><link rel="prefetch" href="/assets/componentPractical.html-4c106614.js" as="script"><link rel="prefetch" href="/assets/directives.html-1374cfb4.js" as="script"><link rel="prefetch" href="/assets/indexes.html-e9face96.js" as="script"><link rel="prefetch" href="/assets/pageContentAuths.html-7e4a0e5b.js" as="script"><link rel="prefetch" href="/assets/pages.html-5c59cfc9.js" as="script"><link rel="prefetch" href="/assets/requestApi.html-815bdaf3.js" as="script"><link rel="prefetch" href="/assets/requestConcept.html-19ae22e9.js" as="script"><link rel="prefetch" href="/assets/requestPractical.html-2adeb105.js" as="script"><link rel="prefetch" href="/assets/requestProxy.html-fbb23d6e.js" as="script"><link rel="prefetch" href="/assets/routerConcept.html-d2000500.js" as="script"><link rel="prefetch" href="/assets/routerPractical.html-67a23ee0.js" as="script"><link rel="prefetch" href="/assets/storeConcept.html-3efb81b4.js" as="script"><link rel="prefetch" href="/assets/storePractical.html-72548894.js" as="script"><link rel="prefetch" href="/assets/typesConcept.html-83bcd54c.js" as="script"><link rel="prefetch" href="/assets/typesPractical.html-a8643161.js" as="script"><link rel="prefetch" href="/assets/basic-old.html-5fa6f14d.js" as="script"><link rel="prefetch" href="/assets/basic.html-82c1a5e3.js" as="script"><link rel="prefetch" href="/assets/dependence.html-f50c9128.js" as="script"><link rel="prefetch" href="/assets/micro-od.html-67e0eb46.js" as="script"><link rel="prefetch" href="/assets/micro.html-882e2183.js" as="script"><link rel="prefetch" href="/assets/404.html-1cace4e3.js" as="script"><link rel="prefetch" href="/assets/demoBlock-547ba88b.js" as="script"><link rel="prefetch" href="/assets/update-log-block-723bb72d.js" as="script"><link rel="prefetch" href="/assets/demo1-12d68d90.js" as="script"><link rel="prefetch" href="/assets/demo2-9eb3d5e3.js" as="script"><link rel="prefetch" href="/assets/demo3-cad48c33.js" as="script"><link rel="prefetch" href="/assets/demo4-00837823.js" as="script"><link rel="prefetch" href="/assets/hideDetail-73eabcb6.js" as="script"><link rel="prefetch" href="/assets/demo1-d30bc42d.js" as="script"><link rel="prefetch" href="/assets/card-49344c01.js" as="script"><link rel="prefetch" href="/assets/cardButton-2ab573df.js" as="script"><link rel="prefetch" href="/assets/custom-2e1d5ce9.js" as="script"><link rel="prefetch" href="/assets/formAndTable-a9e89390.js" as="script"><link rel="prefetch" href="/assets/formFast-68efe74c.js" as="script"><link rel="prefetch" href="/assets/custom-8ee84dfd.js" as="script"><link rel="prefetch" href="/assets/demo1-3e00eea3.js" as="script"><link rel="prefetch" href="/assets/demo1-13d09bea.js" as="script"><link rel="prefetch" href="/assets/coreCustom-44473ea3.js" as="script"><link rel="prefetch" href="/assets/demo1-ffb79487.js" as="script"><link rel="prefetch" href="/assets/moreSearchPopup-e8539b49.js" as="script"><link rel="prefetch" href="/assets/moreSearchPopupTabular-0b018d46.js" as="script"><link rel="prefetch" href="/assets/moreSearchPullDown-a130f024.js" as="script"><link rel="prefetch" href="/assets/moreSearchPullDownTabular-76657876.js" as="script"><link rel="prefetch" href="/assets/selecttion-c7803256.js" as="script"><link rel="prefetch" href="/assets/tabs-d56f6b99.js" as="script"><link rel="prefetch" href="/assets/demo1-0816d60f.js" as="script"><link rel="prefetch" href="/assets/demo2-9ecc5665.js" as="script"><link rel="prefetch" href="/assets/bootstrapLayout-1ea184c9.js" as="script"><link rel="prefetch" href="/assets/controlGroup-e8c42887.js" as="script"><link rel="prefetch" href="/assets/customLabel-4a16a282.js" as="script"><link rel="prefetch" href="/assets/demo1-c21fdd62.js" as="script"><link rel="prefetch" href="/assets/demo2-41d266a2.js" as="script"><link rel="prefetch" href="/assets/demo3-269fd0f6.js" as="script"><link rel="prefetch" href="/assets/demo4-00f66ba2.js" as="script"><link rel="prefetch" href="/assets/demo5-dda7cc5a.js" as="script"><link rel="prefetch" href="/assets/showToolTip-d3b9b379.js" as="script"><link rel="prefetch" href="/assets/uploadDemo-c32953ff.js" as="script"><link rel="prefetch" href="/assets/demo1-b5788180.js" as="script"><link rel="prefetch" href="/assets/demo2-c260ab31.js" as="script"><link rel="prefetch" href="/assets/demo3-6cdf8519.js" as="script"><link rel="prefetch" href="/assets/customColor-3d9de184.js" as="script"><link rel="prefetch" href="/assets/demo0-d1d86d70.js" as="script"><link rel="prefetch" href="/assets/demo1-768aae0e.js" as="script"><link rel="prefetch" href="/assets/demo2-09509e5d.js" as="script"><link rel="prefetch" href="/assets/demo3-7b5c78e1.js" as="script"><link rel="prefetch" href="/assets/demo1-1fef897c.js" as="script"><link rel="prefetch" href="/assets/demo2-9eb823cc.js" as="script"><link rel="prefetch" href="/assets/design-d18997c2.js" as="script"><link rel="prefetch" href="/assets/drawingBoard-b0338214.js" as="script"><link rel="prefetch" href="/assets/bindEvents-dffae645.js" as="script"><link rel="prefetch" href="/assets/classic-0a187567.js" as="script"><link rel="prefetch" href="/assets/contentStorage-975c1b84.js" as="script"><link rel="prefetch" href="/assets/distraction-80ebb968.js" as="script"><link rel="prefetch" href="/assets/form-eaa75a02.js" as="script"><link rel="prefetch" href="/assets/getInstance-23efae27.js" as="script"><link rel="prefetch" href="/assets/inline-6be92b15.js" as="script"><link rel="prefetch" href="/assets/serverUpload-df40118c.js" as="script"><link rel="prefetch" href="/assets/demo1-b740e314.js" as="script"><link rel="prefetch" href="/assets/demo1-68bb6031.js" as="script"><link rel="prefetch" href="/assets/demo2-df4d048d.js" as="script"><link rel="prefetch" href="/assets/demo3-28e0085f.js" as="script"><link rel="prefetch" href="/assets/verticalCenter-129ef695.js" as="script"><link rel="prefetch" href="/assets/demo1-98350cb8.js" as="script"><link rel="prefetch" href="/assets/demo2-7f6ee778.js" as="script"><link rel="prefetch" href="/assets/demo1-f7056bc7.js" as="script"><link rel="prefetch" href="/assets/demo2-a0ba8b6f.js" as="script"><link rel="prefetch" href="/assets/demo1-1c313755.js" as="script"><link rel="prefetch" href="/assets/demo2-c2582bd1.js" as="script"><link rel="prefetch" href="/assets/demo3-a4610510.js" as="script"><link rel="prefetch" href="/assets/demo1-18fbac0d.js" as="script"><link rel="prefetch" href="/assets/demo2-9cab9d84.js" as="script"><link rel="prefetch" href="/assets/demo3-0bbd970b.js" as="script"><link rel="prefetch" href="/assets/demo4-51797bfb.js" as="script"><link rel="prefetch" href="/assets/demo5-43641915.js" as="script"><link rel="prefetch" href="/assets/demo6-b040d95c.js" as="script"><link rel="prefetch" href="/assets/demo7-ce249bbd.js" as="script"><link rel="prefetch" href="/assets/demo8-edf67670.js" as="script"><link rel="prefetch" href="/assets/hideColumnDemo-69627cb7.js" as="script"><link rel="prefetch" href="/assets/oprationColumnConfiger-c237144b.js" as="script"><link rel="prefetch" href="/assets/validate-fbf1b277.js" as="script"><link rel="prefetch" href="/assets/demo1-d9847e60.js" as="script"><link rel="prefetch" href="/assets/demo2-11587063.js" as="script"><link rel="prefetch" href="/assets/demo1-291c9baa.js" as="script"><link rel="prefetch" href="/assets/demo2-52e0c845.js" as="script"><link rel="prefetch" href="/assets/demo3-568b7e8b.js" as="script"><link rel="prefetch" href="/assets/demo4-927e1acc.js" as="script"><link rel="prefetch" href="/assets/avatar-15cf2607.js" as="script"><link rel="prefetch" href="/assets/disabled-433e98ce.js" as="script"><link rel="prefetch" href="/assets/picture-card-c1a8bb4b.js" as="script"><link rel="prefetch" href="/assets/picture-ef3755b5.js" as="script"><link rel="prefetch" href="/assets/preview-f61e7e14.js" as="script"><link rel="prefetch" href="/assets/text-09ef0872.js" as="script"><link rel="prefetch" href="/assets/demo1-a3645ecb.js" as="script"><link rel="prefetch" href="/assets/demo2-d734f7c1.js" as="script"><link rel="prefetch" href="/assets/demo3-0dfdb25a.js" as="script"><link rel="prefetch" href="/assets/demo4-2fb2cce1.js" as="script"><link rel="prefetch" href="/assets/demo5-b421d6bb.js" as="script"><link rel="prefetch" href="/assets/demo6-16ebc159.js" as="script"><link rel="prefetch" href="/assets/demo1-490f80f0.js" as="script"><link rel="prefetch" href="/assets/demo2-e79b66d1.js" as="script"><link rel="prefetch" href="/assets/demo3-f504fcea.js" as="script"><link rel="prefetch" href="/assets/demo4-edeaa9ad.js" as="script"><link rel="prefetch" href="/assets/demo5-f8626895.js" as="script"><link rel="prefetch" href="/assets/demo1-8a123b0e.js" as="script"><link rel="prefetch" href="/assets/demo2-69d4255d.js" as="script"><link rel="prefetch" href="/assets/demo3-2afab6da.js" as="script"><link rel="prefetch" href="/assets/advance-a564dd5c.js" as="script"><link rel="prefetch" href="/assets/demo1-15b4a1ee.js" as="script"><link rel="prefetch" href="/assets/demo2-b3c9e3c3.js" as="script"><link rel="prefetch" href="/assets/demo3-376435ef.js" as="script"><link rel="prefetch" href="/assets/demo4-a8f3de98.js" as="script"><link rel="prefetch" href="/assets/demo5-064b8bb9.js" as="script"><link rel="prefetch" href="/assets/formInside-98b98293.js" as="script"><link rel="prefetch" href="/assets/index-4853382f.js" as="script"><link rel="prefetch" href="/assets/tableInside-481256b6.js" as="script"><link rel="prefetch" href="/assets/closeInit-cb2ef70b.js" as="script"><link rel="prefetch" href="/assets/formInside-4ba7da68.js" as="script"><link rel="prefetch" href="/assets/index-7816f63c.js" as="script"><link rel="prefetch" href="/assets/tableInside-57de18ec.js" as="script"><link rel="prefetch" href="/assets/formInside-e196b3cb.js" as="script"><link rel="prefetch" href="/assets/hideHeader-7f741a3f.js" as="script"><link rel="prefetch" href="/assets/index-06f007ac.js" as="script"><link rel="prefetch" href="/assets/tableInside-8789cc27.js" as="script"><link rel="prefetch" href="/assets/index-43c3d78a.js" as="script">
  </head>
  <body>
    <div id="app"><!--[--><div class="theme-container no-sidebar"><!--[--><header class="navbar"><div class="toggle-sidebar-button" title="toggle sidebar" aria-expanded="false" role="button" tabindex="0"><div class="icon" aria-hidden="true"><span></span><span></span><span></span></div></div><span><a href="/" class=""><img class="logo" src="/favicon.ico" alt="JN Frontend Docs"><span class="site-name can-hide">JN Frontend Docs</span></a></span><div class="navbar-items-wrapper" style=""><!--[--><!--]--><nav class="navbar-items can-hide"><!--[--><div class="navbar-item"><a href="/components/" class="" aria-label="组件库"><!--[--><!--]--> 组件库 <!--[--><!--]--></a></div><div class="navbar-item"><a href="/micro/" class="" aria-label="微前端"><!--[--><!--]--> 微前端 <!--[--><!--]--></a></div><div class="navbar-item"><a href="/micro-cli/" class="" aria-label="micro-cli"><!--[--><!--]--> micro-cli <!--[--><!--]--></a></div><div class="navbar-item"><a href="/utilsDocs/" class="" aria-label="utils"><!--[--><!--]--> utils <!--[--><!--]--></a></div><div class="navbar-item"><div class="navbar-dropdown-wrapper"><button class="navbar-dropdown-title" type="button" aria-label="更新日志"><span class="title">更新日志</span><span class="arrow down"></span></button><button class="navbar-dropdown-title-mobile" type="button" aria-label="更新日志"><span class="title">更新日志</span><span class="right arrow"></span></button><ul style="display:none;" class="navbar-dropdown"><!--[--><li class="navbar-dropdown-item"><a href="/components/UpdateLog.md" class="" aria-label="组件库@3.0.0"><!--[--><!--]--> 组件库@3.0.0 <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/micro/updateLog/basic.md" class="" aria-label="统一管理平台@2.4.0"><!--[--><!--]--> 统一管理平台@2.4.0 <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/micro/updateLog/dependence.md" class="" aria-label="微应用依赖"><!--[--><!--]--> 微应用依赖 <!--[--><!--]--></a></li><!--]--></ul></div></div><!--]--></nav><!--[--><!--]--><button class="toggle-color-mode-button" title="toggle color mode"><svg style="" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M16 12.005a4 4 0 1 1-4 4a4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6a6 6 0 0 0-6-6z" fill="currentColor"></path><path d="M5.394 6.813l1.414-1.415l3.506 3.506L8.9 10.318z" fill="currentColor"></path><path d="M2 15.005h5v2H2z" fill="currentColor"></path><path d="M5.394 25.197L8.9 21.691l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 25.005h2v5h-2z" fill="currentColor"></path><path d="M21.687 23.106l1.414-1.415l3.506 3.506l-1.414 1.414z" fill="currentColor"></path><path d="M25 15.005h5v2h-5z" fill="currentColor"></path><path d="M21.687 8.904l3.506-3.506l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 2.005h2v5h-2z" fill="currentColor"></path></svg><svg style="display:none;" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z" fill="currentColor"></path></svg></button><form class="search-box" role="search"><input type="search" autocomplete="off" spellcheck="false" value><!----></form></div></header><!--]--><div class="sidebar-mask"></div><!--[--><aside class="sidebar"><nav class="navbar-items"><!--[--><div class="navbar-item"><a href="/components/" class="" aria-label="组件库"><!--[--><!--]--> 组件库 <!--[--><!--]--></a></div><div class="navbar-item"><a href="/micro/" class="" aria-label="微前端"><!--[--><!--]--> 微前端 <!--[--><!--]--></a></div><div class="navbar-item"><a href="/micro-cli/" class="" aria-label="micro-cli"><!--[--><!--]--> micro-cli <!--[--><!--]--></a></div><div class="navbar-item"><a href="/utilsDocs/" class="" aria-label="utils"><!--[--><!--]--> utils <!--[--><!--]--></a></div><div class="navbar-item"><div class="navbar-dropdown-wrapper"><button class="navbar-dropdown-title" type="button" aria-label="更新日志"><span class="title">更新日志</span><span class="arrow down"></span></button><button class="navbar-dropdown-title-mobile" type="button" aria-label="更新日志"><span class="title">更新日志</span><span class="right arrow"></span></button><ul style="display:none;" class="navbar-dropdown"><!--[--><li class="navbar-dropdown-item"><a href="/components/UpdateLog.md" class="" aria-label="组件库@3.0.0"><!--[--><!--]--> 组件库@3.0.0 <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/micro/updateLog/basic.md" class="" aria-label="统一管理平台@2.4.0"><!--[--><!--]--> 统一管理平台@2.4.0 <!--[--><!--]--></a></li><li class="navbar-dropdown-item"><a href="/micro/updateLog/dependence.md" class="" aria-label="微应用依赖"><!--[--><!--]--> 微应用依赖 <!--[--><!--]--></a></li><!--]--></ul></div></div><!--]--></nav><!--[--><!--]--><!----><!--[--><!--]--></aside><!--]--><!--[--><main class="page"><!--[--><!--]--><div class="theme-default-content"><!--[--><!--]--><div><h1 id="熟悉而陌生的模块化-全面剖析-commonjs-和-es6module" tabindex="-1"><a class="header-anchor" href="#熟悉而陌生的模块化-全面剖析-commonjs-和-es6module" aria-hidden="true">#</a> 熟悉而陌生的模块化（全面剖析 CommonJs 和 ES6Module）</h1><nav class="table-of-contents"><ul><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#前言" class="router-link-active router-link-exact-active">前言</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#正文开始" class="router-link-active router-link-exact-active">正文开始</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#工程化" class="router-link-active router-link-exact-active"><a name="project" style="color:#000;">工程化</a></a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#模块化" class="router-link-active router-link-exact-active"><a name="module" style="color:#000;">模块化</a></a><ul><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#在没有模块化之前" class="router-link-active router-link-exact-active">在没有模块化之前</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#模块化后" class="router-link-active router-link-exact-active">模块化后</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#说明" class="router-link-active router-link-exact-active">说明</a></li></ul></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#commonjs" class="router-link-active router-link-exact-active">CommonJs</a><ul><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_1-概述" class="router-link-active router-link-exact-active">1. 概述</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_2-基本语法" class="router-link-active router-link-exact-active">2. 基本语法</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_3-特点" class="router-link-active router-link-exact-active">3. 特点</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_4-分析" class="router-link-active router-link-exact-active">4. 分析</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#小结" class="router-link-active router-link-exact-active">小结</a></li></ul></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#es6module" class="router-link-active router-link-exact-active">ES6Module</a><ul><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_1-概述-1" class="router-link-active router-link-exact-active">1. 概述</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_2-基本语法-1" class="router-link-active router-link-exact-active">2. 基本语法</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_3-特点-1" class="router-link-active router-link-exact-active">3. 特点</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#_4-分析-1" class="router-link-active router-link-exact-active">4. 分析</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#小结-1" class="router-link-active router-link-exact-active">小结</a></li></ul></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#总结" class="router-link-active router-link-exact-active">总结</a><ul><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#相同点" class="router-link-active router-link-exact-active">相同点</a></li><li><a aria-current="page" href="/blog/%E7%86%9F%E6%82%89%E8%80%8C%E9%99%8C%E7%94%9F%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96.html#不同点" class="router-link-active router-link-exact-active">不同点</a></li></ul></li></ul></nav><p><img src="/assets/zhuantou-0c0bbffb.jpg" alt="zhuantou"></p><h2 id="前言" tabindex="-1"><a class="header-anchor" href="#前言" aria-hidden="true">#</a> 前言</h2><p>都 2202 年了，还傻傻分不清模块化吗？<br> 面试官问你对模块化的理解，心里明白着，却不知道该怎么回答？<br> 面试官问你 AMD、CMD、UMD、CommonJs 一脸蒙圈？<br> CommonJs 和 ES6 Module 的区别又是什么呢？<br></p><p>别着急，你想知道的不想知道的，你知道的不知道的，你知不知道的，本文都（bu yi ding）有。🙈🙈🙈</p><p><strong>请注意：</strong> 本文篇幅较长，如有兴趣，结合代码食用更佳，还请跟随文章代码敲一敲。</p><p><strong>耐得住寂寞，才能守得住繁华。</strong></p><p><strong>请知悉：</strong> 本文主要内容是用来分析 <strong>CommonJs 规范</strong> 和 <strong>ES6Moudle</strong> 两个模块化方式的，对于其他的模块化方式本文未做分析。</p><p>在本文，你能够收获到：</p><ul><li><a href="#project">前端工程化的概念</a></li><li><a href="#module">模块化的概念、优点</a></li><li>系统的了解 CommonJs 规范 <ul><li><a href="#moduleObj">CommonJs 模块的本质</a></li><li><a href="#exportsModule">暴露模块的方式与机制</a></li><li><a href="#requireModule">加载模块的方式与机制</a></li></ul></li><li>系统的了解 ECMAScript Module <ul><li><a href="#es6ImportExport">暴露与加载的机制</a></li><li><a href="#importTrait">import 执行机制</a></li></ul></li></ul><hr><h2 id="正文开始" tabindex="-1"><a class="header-anchor" href="#正文开始" aria-hidden="true">#</a> 正文开始</h2><p>在现代前端开发中，我想听到最多的应该是工程化、模块化、组件化这几个概念了吧。<br> 或许你不能流畅的描述什么是工程化、模块化、组件化。<br> 但是，你一定用到过。</p><p>你肯定用到过如下指令：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code>npm run serve <span class="token operator">|</span> dev
npm run build
npm run lint
    <span class="token operator">...</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也肯定用到过如下语法：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">const</span> http <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;http&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
    log
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@/utils&quot;</span><span class="token punctuation">;</span>
<span class="token operator">...</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>你也肯定用过如下结构：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token operator">&lt;</span> a <span class="token operator">-</span> button type <span class="token operator">=</span> <span class="token string">&quot;primary&quot;</span> <span class="token operator">&gt;</span> Primary <span class="token operator">&lt;</span> <span class="token operator">/</span>a<span class="token operator">-</span>button<span class="token operator">&gt;</span>
    <span class="token comment">// 或者</span>
    <span class="token operator">&lt;</span>
    el <span class="token operator">-</span> button type <span class="token operator">=</span> <span class="token string">&quot;primary&quot;</span> <span class="token operator">&gt;</span> 主要按钮 <span class="token operator">&lt;</span> <span class="token operator">/</span>el<span class="token operator">-</span>button<span class="token operator">&gt;</span>
    <span class="token operator">...</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>呐，这些都是你日常用到，再熟悉不过的开发方式了对吧。</p><h2 id="工程化" tabindex="-1"><a class="header-anchor" href="#工程化" aria-hidden="true">#</a> <a name="project" style="color:#000;">工程化</a></h2><p><img src="/assets/lou-72ca1772.jpg" alt="gch"></p><p>目前来说，随着浏览器的发展、网络的发展、前端生态圈的发展...<br> 总之时代在进步，人们的需求不断增加，有需求就有业务。<br> 现在，web 业务日益复杂化和多元化，纵观市场上的项目，都已经不再是过去的拼个页面 + 搞几个 jQuery 插件就能完成的了。前端开发已经由 webPage 模式为主转变为以 webApp 模式为主了。运行在 web 端的 app，可见其复杂度。</p><blockquote><p>综上所述，我们开发一个前端项目不再是从画页面，几个页面互相跳转一下的时代。<br> 我们要将项目看做一个工程，从大局出发，一个项目要使用哪些工具，要使用哪些技术，哪些部分是复用的，要如何高效的抽离，如果优化性能，如果加载资源，如何使开发更规范，如何使后期维护更高效等等。</p><p>转换一下，所谓前端工程化是不是就是我们日常开发中使用的 模块化、组件化、规范化、自动化的集合体？<br> 前端工程化是不是前端质的变化呢？</p><p>而对于日常开发中使用的 webpack、vue、angular、react、ant-design、element-ui... 你不能说它们就是前端工程化，它们只是实现前端工程化的方式而已。</p><p>我们要做的是前端工程师，而不是前端页面师。</p></blockquote><p><img src="/assets/banzhuan-bb42f179.jpg" alt="搬砖"></p><p><strong>是不是有点跑题了呢，本文主要目的是说模块化的啊，我觉得工程化还是有必要放在模块化之前提一下的</strong></p><h2 id="模块化" tabindex="-1"><a class="header-anchor" href="#模块化" aria-hidden="true">#</a> <a name="module" style="color:#000;">模块化</a></h2><p>我们已经意识到了前端的 web 程序越来越复杂，也默转潜移的身处于前端工程化的潮流中，是否有种 “初闻不知曲中意，再听已是曲中人” 的意思了呢。</p><p>那 <strong>&quot;模块化&quot;</strong> 又是什么呢？</p><blockquote><p>对于工程化来说，它是工程化的下游分支；<br> 对于 JavaScript 来说，它是一种代码的组织方式；<br> 对于程序来说，它是一种清晰的、易于维护、高效的开发方式。</p></blockquote><h3 id="在没有模块化之前" tabindex="-1"><a class="header-anchor" href="#在没有模块化之前" aria-hidden="true">#</a> 在没有模块化之前</h3><p><strong>你有没有见过这样的代码</strong>：</p><p><img src="/assets/scripts-f6afaba4.png" alt="scripts"></p><p>在很长的一段时间里，前端只能通过一系列的 <code>&lt;script&gt;</code> 标签来维护我们的代码关系，但是一旦我们的项目复杂度提高的时候，这种简陋的代码组织方式便是如噩梦般使得我们的代码变得混乱不堪。<br><strong>并且，这种方式将多个 js 文件一股脑的引入到页面，其实都是在一个全局执行环境下，很容易造成变量污染的问题</strong></p><p><strong>亦或者这样的代码</strong>：</p><p><img src="/assets/codeRowNum-2d3e61d3.png" alt="longcode"></p><p>一个 js 文件里 3000 行代码，一段代码这粘贴一块，那粘贴一块，维护这 3000 行代码，难度可想而知....</p><p><strong>我想从上面的代码不难看出以往开发的痛点在哪里了。</strong></p><h3 id="模块化后" tabindex="-1"><a class="header-anchor" href="#模块化后" aria-hidden="true">#</a> 模块化后</h3><p>我们既然知道痛点在哪里，就应该从痛点出发，去解决问题。<br> 我们思考下，如果要解决上面的几个问题，我们要怎们做？</p><ul><li>首先需要解决多个脚本引入的依赖关系问题 <ul><li>有没有哪种方式能够明确的看到某个脚本依赖哪些脚本？</li><li>并且不用在一股脑的在页面中如此引用，太混乱了。</li></ul></li><li>其次需要解决多个脚本都在一个全局执行环境中，变量都混在一起。 <ul><li>有没有什么方式能够使脚本之间独立运行，互不影响？</li></ul></li><li>然后，某个脚本由于业务复杂，不能都写在一个文件里面 <ul><li>能不能一个脚本实现的业务拆成多个文件，分开管理？</li></ul></li></ul><p>有问题，也就会有解决问题的方式 -- 模块化就为此而生</p><p><strong>概念：</strong></p><ul><li>将一个复杂的程序依据一定的规则（规范）封装成几个块（文件），并进行组合在一起</li><li>块的内部数据与实现是私有的，只是向外部暴露一些接口（方法）与外部其它模块通信</li></ul><blockquote><p>其实模块化就是将一个复杂的系统分解成多个独立的模块的代码组织方式；</p><p><strong>很多人觉得模块化开发的工程意义是复用，其实应该是模块化开发的最大价值应该是分治。不管你将来是否要复用某段代码，你都有充分的理由将其分治为一个模块。</strong></p></blockquote><p><strong>模块化好处：</strong></p><ul><li>避免命名冲突（减少命名空间污染）</li><li>更好的分离，按需加载</li><li>更高复用性</li><li>高可维护性</li></ul><h3 id="说明" tabindex="-1"><a class="header-anchor" href="#说明" aria-hidden="true">#</a> 说明</h3><p>好，说了这么多可算把模块化的概念说完了。</p><p>更多的还有关于模块化的进化过程：</p><blockquote><p>全局 function 模式 =&gt; namespace 模式 =&gt; IIFE 模式 =&gt; IIFE 模式增强 : 引入依赖</p></blockquote><p>具体的几种模块化的规范：</p><blockquote><ul><li>IIFE</li><li>AMD</li><li>CMD</li><li>CommonJS</li><li>UMD</li><li>ES6 Modules</li></ul></blockquote><p>就不再逐一分析，重点还是放到 <strong>CommonJs</strong> 和 <strong>ES6 Modules</strong> 中，因为这两个是目前用的最多的。</p><h2 id="commonjs" tabindex="-1"><a class="header-anchor" href="#commonjs" aria-hidden="true">#</a> CommonJs</h2><h3 id="_1-概述" tabindex="-1"><a class="header-anchor" href="#_1-概述" aria-hidden="true">#</a> 1. 概述</h3><p>随着 Javasript 应用进军服务器端，业界急需一种标准的模块化解决方案，于是，CommonJS 应运而生。这是一种被广泛使用的 Javascript 模块化规范，大家最熟悉的 Node.js 应用中就是采用这个规范。</p><p>在 Node.js 模块系统中，每个文件都被视为一个独立的模块。模块有自己的作用域，一个模块内部所有的变量、函数、类 都是私有的，模块之间不能直接访问模块内部。<br><strong>在服务器端，模块的加载是运行时同步加载的；在浏览器端，模块需要提前编译打包处理。</strong></p><h3 id="_2-基本语法" tabindex="-1"><a class="header-anchor" href="#_2-基本语法" aria-hidden="true">#</a> 2. 基本语法</h3><ul><li><p>暴露模块：</p><ul><li><code>exports.xxx = value</code></li><li><code>module.exports = value</code></li></ul></li><li><p>导入模块：</p><ul><li><code>require(xxx)</code><ul><li>如果是第三方模块，xxx 为模块名；</li><li>如果是自定义模块，xxx 为模块文件路径；</li></ul></li></ul></li></ul><h3 id="_3-特点" tabindex="-1"><a class="header-anchor" href="#_3-特点" aria-hidden="true">#</a> 3. 特点</h3><ul><li>所有代码都运行在模块作用域，不会污染全局作用域。</li><li>模块可以多次加载，但是只会在第一次加载时运行一次，然后运行结果就被缓存了，以后再加载，就直接读取缓存结果。要想让模块再次运行，必须清除缓存。</li><li>模块加载的顺序，按照其在代码中出现的顺序。</li></ul><h3 id="_4-分析" tabindex="-1"><a class="header-anchor" href="#_4-分析" aria-hidden="true">#</a> 4. 分析</h3><p>好，我们大致了解了下 CommonJs，现在让我们逐步分析</p><h4 id="_4-1-module-对象" tabindex="-1"><a class="header-anchor" href="#_4-1-module-对象" aria-hidden="true">#</a> <a name="moduleObj" style="color:#000;">4.1 module 对象</a></h4><p>已知在 node 中，每个文件都是一个独立的模块，那么，这个 “模块” 到底是什么呢？<br> nodejs 官网告诉我们：<strong>在每个模块中都有一个名为 module 的自由变量是对表示当前模块的对象的引用</strong>。</p><p>现在，新建一个 app.js 文件，在里面尝试打印下 module</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>module<span class="token punctuation">)</span><span class="token punctuation">;</span>

node app<span class="token punctuation">.</span>js
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="/assets/logModuleObj-17d1edc8.png" alt="logModule"></p><p>顺利的话，你应该可以看到类似的输出，没错，module 是一个可访问的对象，<br> 而这个对象，就是代表了当前文件(模块)的引用；<br> 现在知道 commonjs 中的 &quot;模块&quot; 究竟是什么了吧。</p><h5 id="module-对象的属性" tabindex="-1"><a class="header-anchor" href="#module-对象的属性" aria-hidden="true">#</a> module 对象的属性</h5><ul><li><p><strong>id：</strong> 模块的标识符。 通常是完全解析后的文件名。</p></li><li><p><strong>exports：</strong> module.exports 对象由 Module 系统创建</p><blockquote><p><strong>exports 属性是重中之重，这个属性是对外的接口，在外部加载模块时，其实加载的是这个模块的 module.exports 属性。我们在暴露属性时，也是通过将属性挂载到 module.exports 上面进行暴露操作的。</strong></p></blockquote></li><li><p><strong>parent：</strong> 标识最先引用该模块的模块。</p></li><li><p><strong>filename：</strong> 模块的完全解析后的文件名。</p></li><li><p><strong>loaded：</strong> 模块是否已经加载完成，或正在加载中。</p></li><li><p><strong>children：</strong> 被该模块引用的模块对象。</p></li><li><p><strong>paths：</strong> 模块的搜索路径。</p></li></ul><h4 id="_4-2-暴露模块" tabindex="-1"><a class="header-anchor" href="#_4-2-暴露模块" aria-hidden="true">#</a> <a name="exportsModule" style="color:#000;">4.2 暴露模块</a></h4><p>在暴露模块时，我们有两种方式来将属性暴露出去：<strong>module.exports 和 exports</strong></p><blockquote><p>exports 是一个对于 module.exports 的更简短的引用形式。<br> exports 变量是在模块的文件级作用域内可用的，且在模块执行之前赋值给 module.exports。</p></blockquote><p><strong>实际上：</strong> <br> 一个模块最终暴露的是 module 整个对象，而在加载时，加载的是 module 对象的 exports 属性；<br><strong>module.exports 始终作为一个模块的输出接口</strong>，以供外部访问内部的变量。</p><p>在一个模块作用域中，还有一个 exports 属性，与 module.exports 属性是同一个引用，指向同一个数据，使用 <code>exports.xxx</code> 的方式，可以将对应的属性挂载到 module.exports 属性上，从而达到暴露属性的目的，如下所示：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module1.js</span>

person <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;Jack&quot;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
    <span class="token literal-property property">sex</span><span class="token operator">:</span> <span class="token string">&quot;man&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">pointPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;point person at module1.js：&quot;</span><span class="token punctuation">,</span> person<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

exports<span class="token punctuation">.</span>person <span class="token operator">=</span> person<span class="token punctuation">;</span>
module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span>pointPerson <span class="token operator">=</span> pointPerson<span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module.exports === exports：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">.</span>exports <span class="token operator">===</span> exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module1：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="/assets/moduleExports-452ce093.png" alt="moduleExports.png"></p><blockquote><p>可以看到 exports 与 module.exports 是同一个引用；</p><p>无论使用 <strong>exports</strong> 还是使用 <strong>module.exports</strong> 都挂载到了 module 下面，也会在将来暴露出去；</p></blockquote><p>如果我们将 module.exports 或者 exports 的引用改变了呢？</p><ol><li>我们先将 exports 的引用改变：</li></ol><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module1.js</span>

person <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;Jack&quot;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
    <span class="token literal-property property">sex</span><span class="token operator">:</span> <span class="token string">&quot;man&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">pointPerson</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;point person at module1.js：&quot;</span><span class="token punctuation">,</span> person<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

exports<span class="token punctuation">.</span>person <span class="token operator">=</span> person<span class="token punctuation">;</span>
module<span class="token punctuation">.</span>exports<span class="token punctuation">.</span>pointPerson <span class="token operator">=</span> pointPerson<span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module.exports === exports：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">.</span>exports <span class="token operator">===</span> exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
<span class="token comment">// console.log(&#39;module1：&#39;, module);</span>

exports <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">index</span><span class="token operator">:</span> <span class="token number">1</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
exports<span class="token punctuation">.</span>a <span class="token operator">=</span> <span class="token string">&quot;aaa&quot;</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module.exports === exports：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">.</span>exports <span class="token operator">===</span> exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module1：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="/assets/resetExports-58a73b52.png" alt="resetExports.png"></p><blockquote><p>承接未更改 exports 引用，对比发现，exports 不再和 moudle.exports 全等，给 exports 添加的属性也没有被添加到 module.exports 上面；</p><p>由于<strong>module.exports 始终作为一个模块的输出接口</strong>，当 exports 与 module.exports 发生断链后，再往 exports 上面添加属性，将不再被暴露出去；</p></blockquote><ol start="2"><li>尝试改变 module.exports 的引用：</li></ol><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module1.js</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">123</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module.exports === exports：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">.</span>exports <span class="token operator">===</span> exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// false</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module1：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="/assets/resetMEx-fdfaca17.png" alt="resetMEx.png"></p><blockquote><p>同样的，exports 与 module.exports 不再全等。在这一步的情况下，exports 还指向旧的 moudle.exports 指向的对象，并未自动的随着 module.exports 的改变而改变；</p><p>区别于改变 exports 的引用，直接改变 module.exports 的引用是真实有效的；最终暴露出去的接口，始终取决于 module.exports 的指向。</p></blockquote><p>如果要改变 module.exports 的引用，大可将 exports 的引用改成同一个引用，如下：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module1.js</span>

module<span class="token punctuation">.</span>exports <span class="token operator">=</span> exports <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">123</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module.exports === exports：&quot;</span><span class="token punctuation">,</span> module<span class="token punctuation">.</span>exports <span class="token operator">===</span> exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_4-3-加载模块" tabindex="-1"><a class="header-anchor" href="#_4-3-加载模块" aria-hidden="true">#</a> <a name="requireModule" style="color:#000;">4.3 加载模块</a></h4><p>在 node 中，加载模块使用的是 require 方法，<strong>这个方法被内置于 node 模块作用域中</strong>，和 module 及 exports 一样，可以直接拿来使用。</p><p>require 在 node 官方给出的解释是这样的：</p><blockquote><p>用于引入模块、JSON、或本地文件。 可以从 node_modules 引入模块。 可以使用相对路径（例如 ./、 ./foo、 ./bar/baz、 ../foo）引入本地模块或 JSON 文件，路径会根据 __dirname 定义的目录名或当前工作目录进行处理。</p></blockquote><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// 引入本地模块：</span>
<span class="token keyword">const</span> myLocalModule <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./path/myLocalModule&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 引入 JSON 文件：</span>
<span class="token keyword">const</span> jsonData <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./path/filename.json&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 引入 node_modules 模块或 Node.js 内置模块：</span>
<span class="token keyword">const</span> crypto <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;crypto&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>require 同步的读入并执行一个 js 文件，并返回这个 js 模块的 module.exports 属性</strong>，如果 js 文件并没有 exports 任何接口，那么它的 module.exports 就是一个空对象，require 返回的也将是这个空对象</p><p>require 还可以引入 json 文件，返回值就是 json 文件内的 json 数据</p><p><strong>上代码：</strong></p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module2.js</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module2.js start：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> person <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;Jack&quot;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
    <span class="token literal-property property">sex</span><span class="token operator">:</span> <span class="token string">&quot;man&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

exports<span class="token punctuation">.</span>person <span class="token operator">=</span> person<span class="token punctuation">;</span>
<span class="token comment">// 暴露出去了一个 quote 变量，使它引用了当前模块的 module.exports 属性</span>
exports<span class="token punctuation">.</span>quote <span class="token operator">=</span> module<span class="token punctuation">.</span>exports<span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module2.js end：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// app.js</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;app.js start：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m2 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;m2：&quot;</span><span class="token punctuation">,</span> m2<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;m2.quote：&quot;</span><span class="token punctuation">,</span> m2<span class="token punctuation">.</span>quote<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;m2.quote === m2：&quot;</span><span class="token punctuation">,</span> m2<span class="token punctuation">.</span>quote <span class="token operator">===</span> m2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;app.js end：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>result：</strong> <br></p><p><img src="/assets/executeStep-3a029692.png" alt="execute"></p><h5 id="解析加载流程" tabindex="-1"><a class="header-anchor" href="#解析加载流程" aria-hidden="true">#</a> 解析加载流程</h5><p>1）在 app.js 开始部分我们打印了一个开始的时间戳，最开始输出的也是这一个<br> 2）代码遇到 require，读入并执行 module2.js<br> 3）在 module2.js 中打印了 module2 开始的时间戳<br> 4）在 module2 中，暴露了一个 person 对象，及一个 module.exports 的引用<br> 5）module2.js 执行完，输出最后一条语句的时间戳<br> 6）执行流返回 app.js，定义的 m2 变量接收 require() 调用的返回值<br> 7）输出 m2 及 m2.quote 属性<br> 8）发现 m2 和 m2.quote 是相等呢，那么是不是可以证明 require 返回的就是 <strong>模块下的 module.exports 属性呢</strong><br> 9）最后输出 app.js 执行完毕的时间戳，其实我们在上面就已经能看出，在执行完 module2.js 后才返回继续执行 app.js，是不是就已经证明了 <strong>require() 是同步读入并执行的</strong>呢。</p><h4 id="加载缓存" tabindex="-1"><a class="header-anchor" href="#加载缓存" aria-hidden="true">#</a> 加载缓存</h4><p>既然 require 会执行 js 文件，如果我多次加载同一模块，是否会执行多次这个 js 文件呢。<br> 我们来试一下：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module2.js 依旧保持上一状态</span>

<span class="token comment">// app.js</span>
<span class="token keyword">const</span> m2 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;第一次加载 module2&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> m3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;第二次加载 module2&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> m4 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;第三次加载 module2&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>result：<br></p><p><img src="/assets/repeatedly-7dff2a5c.png" alt="repeatedly.png"></p><p>咦？不是说 require 会读入并执行 js 文件吗？<br> 怎么就执行了一次 module2.js 呢 <br></p><p>实际上：</p><blockquote><p>在第一次使用 require 加载模块后，这个被加载的模块的 module 属性(对应前面的 <a href="#moduleObj">module 对象</a>)，就被缓存了起来；</p><p>在缓存后，require 就会返回这个缓存中的模块的 module.exports 属性(是否验证了<strong>module.exports 始终作为一个模块的输出接口</strong>这一说法)；</p><p>如果后续还有 require 加载相同的模块(比如 module2)，那么 require 将不会再重新读入且执行那个模块，而是直接将缓存中的对应的模块的 <strong>module.exports</strong> 属性返回；</p><p>对于当前模块来说，无论加载多少次，无论使用什么变量(m2/m3/m4)去接收 require 的返回值，都只不过是引用缓存中的模块对象的 exports 属性而已；</p></blockquote><p>验证：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// app.js</span>

<span class="token keyword">const</span> m2 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m4 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>m2 <span class="token operator">===</span> m3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>m2 <span class="token operator">===</span> m4<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="requer-cache" tabindex="-1"><a class="header-anchor" href="#requer-cache" aria-hidden="true">#</a> requer.cache</h5><p>在 app.js 中尝试打印 require.cache</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// app.js</span>

<span class="token keyword">const</span> m2 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m4 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>require<span class="token punctuation">.</span>cache<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>result: <br></p><p><img src="/assets/cacheObj-e920d544.png" alt="cacheObj"></p><p>虽然我们不能够明确的知道这个到底输出的是个什么东西，不过看这个结构也能猜个七七八八了</p><blockquote><p>我们可以将 require.cache 看做一个对象，缓存对象；<br> 看这个对象的格式，<strong>key</strong> 应该是某些模块的完整路径及模块名字，<strong>value</strong> 应该是对应模块的<a href="#moduleObj">module 对象</a>； 第一个属性是当前模块的 <a href="#moduleObj">module 对象</a>；<br> 其他的属性应该是加载的其他模块的 <a href="#moduleObj">module 对象</a>；<br> 不难看出，require 按照规则，返回的就是这个对象下的某个字段(某个<a href="#moduleObj">module 对象</a>)下的 <code>exports</code> 属性；</p></blockquote><p>我们可以看下代码：</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// app.js</span>

<span class="token keyword">const</span> m2 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m3 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> m4 <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> name <span class="token operator">=</span> require<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">&quot;./modules/module2&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> moduleCache <span class="token operator">=</span> require<span class="token punctuation">.</span>cache<span class="token punctuation">[</span>name<span class="token punctuation">]</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>m2 <span class="token operator">===</span> moduleCache<span class="token punctuation">.</span>exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>m3 <span class="token operator">===</span> moduleCache<span class="token punctuation">.</span>exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>m4 <span class="token operator">===</span> moduleCache<span class="token punctuation">.</span>exports<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// true</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>当我们直接获取 require.cache 对象中的 module2 的属性后，将它的 exports 属性，与 require 加载的模块比较，发现就是全等的；<br> 这样一来，是不是就明白了这个缓存的机制了呢。<br> 如果想要让模块文件再次执行，那就在加载模块前清除掉缓存就可以了（删除掉 require.cache 中代表模块的属性即可）；</p></blockquote><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">clearCache</span><span class="token punctuation">(</span><span class="token parameter">path</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    path <span class="token operator">=</span> require<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">delete</span> require<span class="token punctuation">.</span>cache<span class="token punctuation">[</span>path<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在 app 模块中，大概就像下图这样：<br></p><p><img src="/assets/CommonJSContent-2d3e5589.png" alt="CommonJSContent.png"></p><p><strong>【注意：】</strong> 如果你能弄明白这个加载的缓存机制，也就能够明白为什么 commonjs 中加载的模块为什么不能实时响应模块内部数据的变化了。 <strong>因为模块加载的是被加载模块的一个缓存副本，并不能实时的响应模块内部的数据的变化</strong></p><h3 id="小结" tabindex="-1"><a class="header-anchor" href="#小结" aria-hidden="true">#</a> 小结</h3><ul><li><p>在 node 中，每个文件都是独立的模块；</p></li><li><p>在每个模块中，都有一个名为 module 的自由变量，用来表示当前模块的引用；</p></li><li><p>module 对象下面的 exports 属性是最终引用的关键属性</p></li><li><p>暴露模块有两种方式，module.exports &amp;&amp; exports</p><ul><li>exports 是 module.exports 的简写</li><li>它们两个在最初时指向同一个地址</li><li>改变其中任意一个，都会使 exports 和 moudle.exports 断链</li><li>最终暴露出去的接口，完全取决于 module.exports 属性</li></ul></li><li><p>加载模块使用 require 方法；</p></li><li><p>加载模块时会将被加载模块的 module 对象缓存在当前模块中的 require.cache 中；</p></li><li><p>正式因为加载的缓存机制，加载过后的模块不能实时获取模块内部的数据。</p></li></ul><h2 id="es6module" tabindex="-1"><a class="header-anchor" href="#es6module" aria-hidden="true">#</a> ES6Module</h2><h3 id="_1-概述-1" tabindex="-1"><a class="header-anchor" href="#_1-概述-1" aria-hidden="true">#</a> 1. 概述</h3><p>ES6 在语言标准的层面上，实现了模块功能，而且实现得相当简单，完全可以取代 CommonJS 和 AMD 规范，成为浏览器和服务器通用的模块解决方案。</p><p>ES6 模块的设计思想是尽量的静态化，使得编译时就能确定模块的依赖关系，以及输入和输出的变量。 CommonJS 和 AMD 模块，都只能在运行时确定这些东西。 比如，CommonJS 模块就是对象，只有在执行之后才能获取到 <a href="#moduleObj">module 对象</a>， 加载时必须查找对象属性( module.exports )。</p><h3 id="_2-基本语法-1" tabindex="-1"><a class="header-anchor" href="#_2-基本语法-1" aria-hidden="true">#</a> 2. 基本语法</h3><ul><li><p>暴露模块</p><blockquote><p>export 命令用于规定模块的对外接口</p></blockquote><ul><li>export const a = &#39;value&#39;</li><li>export { prop1, prop2, prop3 }</li><li>export { prop as changeName }</li></ul></li><li><p>加载模块</p><blockquote><p>import 命令用于输入其他模块提供的功能</p></blockquote><ul><li>import { prop1, prop2, prop3 } from &#39;module&#39;</li><li>import { prop1 as changeName } from &#39;module&#39;</li></ul></li></ul><h3 id="_3-特点-1" tabindex="-1"><a class="header-anchor" href="#_3-特点-1" aria-hidden="true">#</a> 3. 特点</h3><ul><li>ECMAScript 语言标准提供；</li><li>一个文件就是一个模块；</li><li>静态化，编译时就能确定模块的依赖关系，以及输入和输出的变量；</li><li>模块内自动严格模式；</li><li>加载是值的引用，可以实时拿到模块的数据；</li><li>前后端都适用。</li></ul><h3 id="_4-分析-1" tabindex="-1"><a class="header-anchor" href="#_4-分析-1" aria-hidden="true">#</a> 4. 分析</h3><p>import 和 export 是 ES6 语言本身提供给我们模块化的命令，可以说是 关键字。</p><h4 id="_4-1-机制-接口" tabindex="-1"><a class="header-anchor" href="#_4-1-机制-接口" aria-hidden="true">#</a> <a name="es6ImportExport" style="color:#000;">4.1 机制，接口</a></h4><h5 id="暴露" tabindex="-1"><a class="header-anchor" href="#暴露" aria-hidden="true">#</a> 暴露</h5><p>export 命令规定的是<strong>对外的接口</strong>，必须与模块内部的变量建立一一对应关系。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">export</span> <span class="token number">1</span> <span class="token comment">// 报错</span>

<span class="token keyword">const</span> m <span class="token operator">=</span> <span class="token number">2</span>
<span class="token keyword">export</span> m <span class="token comment">// 报错</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面两种写法都会报错，因为没有提供对外的接口。第一种写法直接输出 1，第二种写法通过变量 m，还是直接输出 1。1 只是一个值，不是接口。</p><p>正确的写法是下面这样。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// 写法一</span>
<span class="token keyword">export</span> <span class="token keyword">var</span> m <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>

<span class="token comment">// 写法二</span>
<span class="token keyword">var</span> m <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span>
    m
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// 写法三</span>
<span class="token keyword">var</span> n <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span>
    n <span class="token keyword">as</span> m
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面三种写法都是正确的，规定了对外的接口 m。其他脚本可以通过这个接口，取到值 1。它们的实质是，在接口名与模块内部变量之间，建立了一一对应的关系。</p><p>另外，<strong>export 语句输出的接口</strong>，与其对应的值是动态绑定关系，即通过该接口，可以取到模块内部实时的值。</p><h5 id="加载" tabindex="-1"><a class="header-anchor" href="#加载" aria-hidden="true">#</a> 加载</h5><p>使用 export 命令定义了模块的对外接口以后，其他 JS 文件就可以通过 import 命令加载这个模块。</p><p>import 命令输入的变量都是只读的，因为它的<strong>本质是输入接口</strong>。也就是说，不允许在加载模块的脚本里面，改写接口。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span>
    a
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./xxx.js&quot;</span><span class="token punctuation">;</span>

a <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Syntax Error : &#39;a&#39; is read-only;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面代码中，脚本加载了变量 a，对其重新赋值就会报错，因为 a 是一个只读的接口（是接口，也是变量，接口与变量大概是对等的）。</p><p>但是，如果 a 是一个对象，改写 a 的属性是允许的（对象引用地址，可以改写对象的属性，但不能更改对象的引用）。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span>
    a
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./xxx.js&quot;</span><span class="token punctuation">;</span>

a<span class="token punctuation">.</span>foo <span class="token operator">=</span> <span class="token string">&quot;hello&quot;</span><span class="token punctuation">;</span> <span class="token comment">// 合法操作</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="result" tabindex="-1"><a class="header-anchor" href="#result" aria-hidden="true">#</a> Result</h5><blockquote><p>对于 export 暴露出去的东西，及 import 加载的东西，应该怎么解读？<br></p><p>export 输出接口，这个输出接口与模块内部变量、函数或类，建立引用关系，通过这个<strong>接口</strong>可以实时的获取到模块内的数据；<br> import 输入接口，import 命令在模块内创建输入接口，将被加载模块中同样名字的 &quot;输出接口&quot; (<strong>注意：是输出接口</strong>不是内部变量) 对接，这样一来主模块中就可以根据 &quot;接口&quot; 建立的连接，去访问被加载模块中的变量、函数或类。由于是引用关系，所以拿到的数据是实时的；</p><p>大体意思就是 import 和 export 之间通过接口连接，建立引用关系，a 模块 去获取 b 模块 暴露出来的功能。<br></p></blockquote><p>大致如下：(只是帮助理解这个接口，我并不太清楚 js 的底层到底如何去划分的)</p><p><img src="/assets/exportImport-c0d2ac19.png" alt="exportImport.png"></p><p><strong>【注意：】</strong> 虽然引用类型数据可以通过地址，可以直接在模块外修改数据，这样一来，其他模块也可以读到改写后的值，这种方式会导致很难查错，建议凡是输入的变量，都当作完全只读，不要轻易改变它的属性。</p><h4 id="_4-2-import-特性" tabindex="-1"><a class="header-anchor" href="#_4-2-import-特性" aria-hidden="true">#</a> <a name="importTrait" style="color:#000;">4.2 import 特性</a></h4><h5 id="提升" tabindex="-1"><a class="header-anchor" href="#提升" aria-hidden="true">#</a> 提升</h5><p>import 命令具有提升效果，会提升到整个模块的头部，首先执行（类似于变量提升，原理百度 js 的预编译阶段）</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token function">foo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token punctuation">{</span>
    foo
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;my_module&quot;</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的代码不会报错，因为 import 的执行早于 foo 的调用。这种行为的本质是，import 命令是编译阶段执行的，在代码运行之前。</p><h5 id="静态执行" tabindex="-1"><a class="header-anchor" href="#静态执行" aria-hidden="true">#</a> 静态执行</h5><p>由于 import 是在 预编译阶段执行的，所以不能使用表达式和变量，因为这些只有在代码运行阶段才能得到结果。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// 报错</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
    <span class="token string">&#39;f&#39;</span> <span class="token operator">+</span> <span class="token string">&#39;oo&#39;</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;my_module&#39;</span><span class="token punctuation">;</span>

<span class="token comment">// 报错</span>
<span class="token keyword">let</span> module <span class="token operator">=</span> <span class="token string">&#39;my_module&#39;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
    foo
<span class="token punctuation">}</span> from module<span class="token punctuation">;</span>

<span class="token comment">// 报错</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">import</span> <span class="token punctuation">{</span>
        foo
    <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;module1&#39;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
    <span class="token keyword">import</span> <span class="token punctuation">{</span>
        foo
    <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&#39;module2&#39;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面三种写法都会报错，因为它们用到了表达式、变量和 if 结构。在静态分析阶段，这些语法都是没法得到值的。</p><p><strong>【注意：】</strong> CommonJS 模块的 require 命令和 ES6 模块的 import 命令，可以写在同一个模块里面，但是最好不要这样做。因为 import 在静态解析阶段执行，所以它是一个模块之中最早执行的。</p><h5 id="执行模块" tabindex="-1"><a class="header-anchor" href="#执行模块" aria-hidden="true">#</a> 执行模块</h5><p>import 也是会执行所加载的模块的（require 也会执行被加载的模块），因此可以有下面的写法</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token string">&quot;lodash&quot;</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>上面代码仅仅执行 lodash 模块，但是不输入任何值。</p><p>如果多次重复执行同一句 import 语句，那么只会执行一次，而不会执行多次。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token string">&quot;lodash&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token string">&quot;lodash&quot;</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><h5 id="试一下" tabindex="-1"><a class="header-anchor" href="#试一下" aria-hidden="true">#</a> 试一下</h5><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// module1.js</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module1 start at：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token keyword">let</span> person <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">&quot;Jack&quot;</span><span class="token punctuation">,</span>
    <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">18</span><span class="token punctuation">,</span>
    <span class="token literal-property property">sex</span><span class="token operator">:</span> <span class="token string">&quot;man&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;module1 end at：&quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// app.js</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;app start at &quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
    person
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./module1.js&quot;</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;app end at &quot;</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>看一下会如何输出</p><h4 id="_4-3-import" tabindex="-1"><a class="header-anchor" href="#_4-3-import" aria-hidden="true">#</a> 4.3 import()</h4><p>import 命令会被 JavaScript 引擎静态分析，先于模块内的其他语句执行。所以，下面的代码会报错。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token comment">// 报错</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">import</span> MyModual <span class="token keyword">from</span> <span class="token string">&quot;./myModual&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面代码中，引擎处理 import 语句是在编译时，这时不会去分析或执行 if 语句，所以 import 语句放在 if 代码块之中毫无意义，因此会报语法错误，而不是执行时错误。</p><p>也就是说，<strong>import 和 export 命令只能在模块的顶层</strong>，不能在代码块之中（比如，在 if 代码块之中，或在函数之中）。</p><p>这样的设计，固然有利于编译器提高效率，但也导致<strong>无法在运行时加载模块</strong>。在语法上，条件加载就不可能实现。如果 import 命令要取代 Node 的 require 方法，这就形成了一个障碍。因为 <strong>require 是运行时加载模块</strong>，import 命令无法取代 require 的动态加载功能。</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token string">&quot;./&quot;</span> <span class="token operator">+</span> fileName<span class="token punctuation">;</span>
<span class="token keyword">const</span> myModual <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>上面的语句就是动态加载，require 到底加载哪一个模块，只有运行时才知道。import 命令做不到这一点。</p><h5 id="import-函数" tabindex="-1"><a class="header-anchor" href="#import-函数" aria-hidden="true">#</a> import()函数</h5><p>ES2020 提案 引入 import()函数，支持动态加载模块。(node v8 还未支持此语法函数，需要使用 babel)</p><div class="language-javascript line-numbers-mode" data-ext="js"><pre class="language-javascript"><code><span class="token keyword">import</span><span class="token punctuation">(</span>specifier<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>上面代码中，import 函数的参数 specifier，指定所要加载的模块的位置。import 命令能够接受什么参数，import()函数就能接受什么参数，两者区别主要是后者为<strong>动态加载</strong>。</p><p>import()函数可以用在任何地方，不仅仅是模块，非模块的脚本也可以使用。<br> 它是运行时执行，也就是说，什么时候运行到这一句，就会加载指定的模块。<br> 另外，import()函数与所加载的模块没有静态连接关系（也就是说，<strong>使用 import() 函数加载的模块下的数据并不是实时的</strong>），这点也是与 import 语句不相同。<br> import()类似于 Node 的 require 方法，区别主要是前者是<strong>异步加载</strong>，后者是<strong>同步加载</strong>。</p><p>import()加载模块成功以后，这个模块会作为一个对象，<strong>当作 then 方法的参数</strong>。因此，可以使用对象解构赋值的语法，获取输出接口。</p><h3 id="小结-1" tabindex="-1"><a class="header-anchor" href="#小结-1" aria-hidden="true">#</a> 小结</h3><ul><li>由于历史原因，ES6 JS 终于迎来了语言本身的模块化</li><li>暴露模块使用 export 命令</li><li>加载模块使用 import 命令 <ul><li>import 命令也会执行模块文件</li></ul></li><li>暴露和加载的本质是 <strong>“接口”</strong><ul><li>输出接口 必须与模块内部变量一一建立对应关系</li><li>加载的接口是只读的，不允许改变</li><li>复杂类型数据，由于接口对接的是引用，故可以改变数据下的字段，但不能修改引用</li></ul></li><li>暴露和加载的关系是 <strong>“引用”</strong><ul><li>加载的数据与被加载模块内的数据是实时的</li></ul></li><li>加载是在 js 预编译阶段完成的</li><li>import 和 export 命令只能放到模块作用域的顶层，不能放到任何流程语句中，否则会报语法错误</li><li>新提出的 import() 函数，能够异步加载模块，可以在执行阶段进行加载模块</li></ul><h2 id="总结" tabindex="-1"><a class="header-anchor" href="#总结" aria-hidden="true">#</a> 总结</h2><p>一篇文章下来，模块化这方面清晰了不少，也总算系统的将 commonjs 和 es6 module 做了比较，收获良多。<br><strong>一份耕耘，一份收获吧</strong> <br> 文章结尾，将 CommonJs 和 ES6Module 做个对比：</p><h3 id="相同点" tabindex="-1"><a class="header-anchor" href="#相同点" aria-hidden="true">#</a> 相同点</h3><ul><li>都是以一个文件就是一个模块的标准划分模块</li><li>模块有单独的作用域，外部不可直接访问模块内部变量，需要暴露出去，以供其他模块操作</li></ul><h3 id="不同点" tabindex="-1"><a class="header-anchor" href="#不同点" aria-hidden="true">#</a> 不同点</h3><ul><li>大环境 <ul><li>CommonJs 并非语言层面的模块化，而是一种社区规范，NodeJs 引用此规范，大多适用于 node 中</li><li>ES6Module 是真正语言层面的模块化，是 ECMAScript 提供的，适用于前后端</li></ul></li><li>模块化机制 <ul><li>CommonJs 是 node 环境中，当一个模块化运行完毕后，才能得到这个模块</li><li>ES6Module 是在 JS 预编译阶段就确定了模块的依赖关系的，做了静态优化</li></ul></li><li>暴露机制 <ul><li>CommonJs 在模块执行完成后，将模块中的 <a href="#moduleObj">module 对象</a> 暴露出去</li><li>ES6Module 暴露的是与内部变量建立引用关系的接口</li></ul></li><li>加载机制 <ul><li>CommonJs 使用 require 在执行完 js 后，将暴露的 <a href="#moduleObj">module 对象</a> 缓存在 require.cache 中，并返回这个模块对象的 exports 属性，供当前模块操作，加载了整个模块(包括不必要的地方)</li><li>ES6Module 使用 import 在预编译阶段仅会加载模块对应的接口，并不会加载整个模块</li></ul></li><li>访问机制 <ul><li>CommonJs 在加载完模块后，由于是在内部缓存的，所以是不能实时的响应被加载模块内部数据的变化的</li><li>ES6Module 由于是输入接口与输出接口的对接，且输出接口与内部建立引用关系，所以主模块能够实时的获取到被加载模块内的数据</li></ul></li><li>加载命令机制 <ul><li>require <ul><li>同步的</li><li>在执行阶段才步读入并执行 js 的</li><li>可以放在流程控制语句中</li></ul></li><li>import <ul><li>同步的</li><li>在预编译阶段就会执行 js，并对接其输出接口</li><li>不可以放在流程控制语句中，只能放在模块作用域的顶层</li></ul></li><li>import() <ul><li>异步的</li><li>可以放到流程控制语句中</li><li>返回一个 Promise</li><li>返回的模块对象以参数的形式返回给 .then</li><li>返回的模块对象，不再与模块内部对接(不再是实时的)</li></ul></li></ul></li></ul><!-- ## 参考文章

[前端模块化详解(完整版)](https://juejin.im/post/5c17ad756fb9a049ff4e0a62)<br>
[前端模块化的前世今生](https://www.cnblogs.com/scq000/p/10647128.html)<br>
[浅谈前端工程化](https://www.cnblogs.com/onebox/p/9570518.html)<br>
[NodeJs - Module](http://nodejs.cn/api/modules.html)<br>
[ES6 - Module](http://es6.ruanyifeng.com/#docs/module)

--></div><!--[--><!--]--></div><footer class="page-meta"><!----><div class="meta-item last-updated"><span class="meta-item-label">上次更新: </span><!----></div><div class="meta-item contributors"><span class="meta-item-label">贡献者: </span><span class="meta-item-info"><!--[--><!--[--><span class="contributor" title="email: 18651805393@163.com">Zyunchao</span><!----><!--]--><!--]--></span></div></footer><!----><!--[--><!--]--></main><!--]--></div><!----><!--]--></div>
    <script type="module" src="/assets/app-bfaa94ab.js" defer></script>
  </body>
</html>
